////////////// DEBUG ////////////////////////////////
#define       speed_debug     false    // Die Kontraktschlüsse
#define       tacho_debug     false   // Die Durchläufe etc -> das willst du nicht wirklich auf true setzen
#define       clock_debug     false   // haha fehler gefunden -> nie wieder abs() nutzen
#define       fuel_debug      false    // sehen ob die tropfen durchlaufen
#define       storage_debug   true   // sehen ob das Datum richtig geladen wird
#define       blinker_debug   false   // sehen wie der Blinkerstate ist
////////////// DEBUG ////////////////////////////////
////////////// DISPLAY ///////////////////////////////////
#include      <ks0108.h>
#include      <Arial14.h>         // proportional font
#include      <SystemFont5x7.h>   // system font
int           zeile;
int           disp_brightness;
int           disp_contrast;
int           disp_gnd_pin=32;
int           disp_backlight_pin=5;
int           disp_contrast_pin=12;
////////////// DISPLAY ///////////////////////////////////
////////////// DCF 77 / RTC_DS1307 ///////////////////////
#include      <Wire.h>
#include      <MsTimer2.h>
char          clock_out[9] ="";
unsigned int  time_valid;
////////////// DCF 77 / RTC_DS1307 ///////////////////////
////////////// temperature ///////////////////////////////
boolean       temp_valid=false;
int           temp_position=0;

int           oil_temp_out1=0;
int           oil_temp_out2=0; 

int           air_temp_out1=0;
int           air_temp_out2=0; 
 ////////////// temperature ///////////////////////////////////
////////////// DZ ///////////////////////////////////
unsigned long dz_out_disp=0; // to show on display, rounded by 50
unsigned long dz_out_calc=0; // real rotation speed
int           dz_ps=0; 
////////////// DZ ///////////////////////////////////
///////////// speed ///////////////////////////////////
unsigned long speed_last_valid_time=millis(); 
unsigned long right_now;
int           speed_out_kmh=0;
///////////// speed ///////////////////////////////////
///////////// store ///////////////////////////////////
#include      <EEPROM.h>
boolean       storage_outdated=false;
///////////// store ///////////////////////////////////
///////////// sprint ///////////////////////////////////
boolean       sprint_done=false;
boolean       sprint_lock=false;
boolean       sprint_blink_show=false;
unsigned long sprint_start;
unsigned long sprint_end;
///////////// sprint ///////////////////////////////////
///////////// fuel ///////////////////////////////////
unsigned long fuel_last_time_called=millis();
int           fuel_refresh=1000;
int           fuel_last_value;
unsigned int  fuel_anzahl=500; // samples pro 0.1 Liter 
///////////// fuel ///////////////////////////////////
///////////// menu ///////////////////////////////////
unsigned long menu_button_time=millis();
int           menu_state=11;
unsigned long menu_button_first_push=millis();
int           menu_button_timeout=300; // wartezeit zwischen 2 steps
int           menu_button_fast_delay=menu_button_timeout*10; // wartezeit bis schneller
int           menu_button_fast_timeout=100;  // wartezeit zwischen 2 steps -> schnell
///////////// menu ///////////////////////////////////
//////////////// blinker //////////////////////////////
short int     blinker_pin=6;
boolean       blinker_lock=false;
unsigned long blinker_start=0;
short int     blinker_timeout=30; // 30 sek bis nachfrage
//////////////// blinker //////////////////////////////
//////////////// disp backup //////////////////////////////
unsigned long disp_zeile_bak[9];
//////////////// disp backup //////////////////////////////
///////////// Vars ////////////////////////////////////
unsigned long cpr=0; // zum zählen der cycles
int           refresh_interval=600; // display refresh
unsigned long previousMillis = 0; // wächter über den display refresh

int           fuel_added=90; // predefined value "added fuel"
unsigned long max_speed[9];
unsigned long avg_speed[9];
unsigned long avg_timebase[9];
unsigned long trip_dist[9];
short int     trip_mode;
short int     flasher_1_mode;
short int     flasher_2_mode;
///////////// Vars ////////////////////////////////////

/**
 * The interrupt routine for counting seconds - increment hh:mm:ss.
 */
void every_sec() {
  clock_inc();
  get_temps();
  km_save();
  blinker();
};


///////////// Startup //////////////////
void setup() {
  Serial.begin(9600);
  Serial.println("=== Auf geht's ===");
  DCF77Init();
  store_init();
  dz_init();
  speed_init();
  menu_init();
  temp_init();
  blinker_init();
  disp_init();
//  fuel_init();
  menu_disp();
  // every second to count
  MsTimer2::set(1000, every_sec);  
  MsTimer2::start();
  // reset backup
  for(int i=0;i<sizeof(disp_zeile_bak)/sizeof(disp_zeile_bak[0]);i++){
    disp_zeile_bak[i]=0;
  };
  Serial.println("=== Setup finished ===");
};
///////////// Startup //////////////////
///////////// Loop this //////////////////
void loop(){ 
  if(tacho_debug){
    Serial.print("Loop Durchlauf, menustate ist ");
    Serial.print(menu_state);
    Serial.print("\n");
  };
  cpr++;
  // unverständlich, aber hier aufrufen, sonst crash
  if(time_valid==1){
    clock_store();
    time_valid++;
  };
  ////// menü taster abfrage
  int menu_state_old=menu_state;
  menu_state=menu_button_test();   
  if(menu_state>-1){
    Serial.print("State changed: was ");
    Serial.print(menu_state_old);
    Serial.print(" and is now ");
    Serial.print(menu_state);
    Serial.print(" Calling menu();\n");
    menu_button_time=millis();
    menu_disp();
  } 
  else {
    menu_state=menu_state_old;
  };
  ////// menü taster abfrage  
  //////////////////// bestimmte anzeigen -> aktualisierungsintervall ///////////////////
  //////////////////// Normaler Tacho ///////////////////
  if((menu_state/10)==1)  {
    previousMillis=millis(); // stoppen wie lange wir brauchen
    if(tacho_debug){
      Serial.println("Normaler Tacho Durchlauf");
    };
    // positions berechnung für die Zeilen
    zeile=0; // wird benutzt von get_zeile
    int zeilen=4;
    int y; // aktuelle y position
    // zeilen 9,17,25,33,41,49 je 8 pixel hoch
     ///// öl temp ////// 
    // außen fixe position
    if( (disp_zeile_bak[6]!=oil_temp_out1 && temp_valid) || (!temp_valid && disp_zeile_bak[6]!=temp_position+200)){
      GLCD.FillRect(22,0,29,7,WHITE); 
      GLCD.GotoXY(22,0);
      if(temp_valid){
        disp_zeile_bak[6]=oil_temp_out1;
        char oil_temp_out[6] ="";
        sprintf(oil_temp_out,"%3i.%iC",oil_temp_out1,oil_temp_out2);
        GLCD.Puts(oil_temp_out);
      } 
      else {
        disp_waiting(temp_position);
        disp_zeile_bak[6]=temp_position+200;
      };
    };
    ///// öl temp //////  
    //// air temp //////
    // außen fixe position
    if( (disp_zeile_bak[5]!=air_temp_out1 && temp_valid) || (!temp_valid && disp_zeile_bak[5]!=(temp_position+200))){
      GLCD.FillRect(98,0,20,7,WHITE);
      GLCD.GotoXY(98,0);
      if(temp_valid){
        disp_zeile_bak[5]=air_temp_out1;
        char air_temp_out[13] ="";
        sprintf(air_temp_out,"%2i.%iC\n",air_temp_out1,air_temp_out2);
        GLCD.Puts(air_temp_out);
      } 
      else {
        disp_waiting(temp_position%4);
        disp_zeile_bak[5]=temp_position+200;
      };
    };
    ///// air temp //////
    ///// speed //////  
    // innen position berechnen:
    y=get_zeile(zeilen);
    char speed_out_s[8];
    int temp_speed=speed_copy();
    if(disp_zeile_bak[0]==0){   // zeile 0 noch nicht geschrieben, schreibe die km/h
      sprintf(speed_out_s,"%3i km/h",temp_speed);
      GLCD.FillRect(0,y,128,7,WHITE);
      GLCD.GotoXY(40,y);
      GLCD.Puts(speed_out_s);
      disp_zeile_bak[0]=temp_speed+1; // haben wir auch im stand nicht diese schleife
    }                                                  // war schon mal in zeile 0 => schreibe nur die zahl, das aber auch nur wenn 1!=x+1 man also nicht steht, bzw stand...
    else if( (abs(disp_zeile_bak[0]-(temp_speed+1))>1) || (abs(disp_zeile_bak[0]-(temp_speed+1))==1 && temp_speed<10) ) { // nur aktualisieren wenn differ 2 km/h oder unter 10 km/h und 1 km/h differ
    //else if(abs(disp_zeile_bak[0]-(temp_speed+1))>1){
      sprintf(speed_out_s,"%3i",temp_speed);
      disp_zeile_bak[0]=temp_speed+1;
      GLCD.FillRect(40,y,18,7,WHITE);
      GLCD.GotoXY(40,y);
      GLCD.Puts(speed_out_s);
    };
    ///// speed //////
    //\\\\\\\\\\\//// var anzeige //////\\\\\\\\\\\\\\
    // innen position berechnen:
    y=get_zeile(zeilen);
    char char_buffer[20]; 
    // ab hier unterschiedliche ausgabe:
    switch(menu_state%10){
    case 1:       /////// dz  ////   
      dz_copy();
      if(disp_zeile_bak[1]!=dz_out_disp+1){
        if(disp_zeile_bak[1]==0){ //schreib alles neu, auch die buchstaben
          sprintf(char_buffer,"%5lu U/min | %2i PS",dz_out_disp,dz_ps);
          GLCD.FillRect(0,y,128,7,WHITE);
          GLCD.GotoXY(4,y);
          GLCD.Puts(char_buffer);
        } 
        else { // nur eine änderung im wert
          sprintf(char_buffer,"%5lu",dz_out_disp);
          GLCD.FillRect(4,y,30,7,WHITE);
          GLCD.GotoXY(4,y);
          GLCD.Puts(char_buffer);
          sprintf(char_buffer,"%2i",dz_ps);
          GLCD.FillRect(88,y,12,7,WHITE);
          GLCD.GotoXY(88,y);
          GLCD.Puts(char_buffer); 
        };
        disp_zeile_bak[1]=dz_out_disp+1;
      };
      break;     ////// dz  ////
    case 2:  
      sprintf(char_buffer,"Non permanent");  
      break;
    case 3:  
      sprintf(char_buffer,"     Day     ");  
      break;
    case 4:  
      sprintf(char_buffer,"    Tour     ");  
      break;
    case 5:  
      sprintf(char_buffer,"    Fuel     ");  
      break;
    case 6:  
      sprintf(char_buffer,"     Q1      ");  
      break;
    case 7:  
      sprintf(char_buffer,"     Q2      ");  
      break;
    case 8:  
      sprintf(char_buffer,"     Q3      ");  
      break;
    case 9:  
      sprintf(char_buffer,"   Saison    ");  
      break;
    };
    // damit sollten die states 002 bis 009 abgedeckt sein
    if(menu_state%10>1){ 
      if((menu_state%10)!=disp_zeile_bak[1]){
        GLCD.FillRect(0,y,128,7,WHITE);
        GLCD.GotoXY(24,y);
        GLCD.Puts(char_buffer);
        disp_zeile_bak[1]=(menu_state%10);
      };
      y=get_zeile(zeilen);

      if(disp_zeile_bak[2]!=(int)round(avg_speed[(menu_state%10)-2]/avg_timebase[(menu_state%10)-2])+1+(int)max_speed[(menu_state%10)-2]){
        disp_zeile_bak[2]=(int)round(avg_speed[(menu_state%10)-2]/avg_timebase[(menu_state%10)-2])+1+(int)max_speed[(menu_state%10)-2];
        GLCD.FillRect(0,y,128,7,WHITE);
        GLCD.GotoXY(0,y);
        sprintf(char_buffer,"A: %3ikm/h M: %3ikm/h",(int)round(avg_speed[(menu_state%10)-2]/avg_timebase[(menu_state%10)-2]),(int)max_speed[(menu_state%10)-2]);
        GLCD.Puts(char_buffer);
      };
      
      if(disp_zeile_bak[3]!=avg_timebase[(menu_state%10)-2]+1){
        disp_zeile_bak[3]=avg_timebase[(menu_state%10)-2]+1;
        sprintf(char_buffer,"%02i:%02i:%02i  %5i,%02i km",(int)round(avg_timebase[(menu_state%10)-2]/3600),(int)round((avg_timebase[(menu_state%10)-2]%3600)/60),(int)round(avg_timebase[(menu_state%10)-2]%60),(int)floor(trip_dist[(menu_state%10)-2]/1000),(int)floor((trip_dist[(menu_state%10)-2]%1000)/10));
        y=get_zeile(zeilen);
        GLCD.FillRect(0,y,128,7,WHITE); 
        GLCD.GotoXY(0,y);
        GLCD.Puts(char_buffer);
      };
    } 
    ///// Leistung / Warnung //////  für 001 gibts die Möglichkeit: Warnung oder entsprechend des trip mode den trip   
    else {
      /// warnung wegen zu hoher Drehzahl
      if(oil_temp_out1<60 && dz_out_disp>7000){ 
        y=get_zeile(zeilen);
        if(disp_zeile_bak[3]!=-1){ // erst die bedingung um den Block abzuklopfen dann gucken ob refresh!
          GLCD.FillRect(0,y,128,15,WHITE);
          GLCD.GotoXY(25,y);
          GLCD.Puts("!! Warnung !!");
          y=get_zeile(zeilen);
          GLCD.GotoXY(18,y);
          GLCD.Puts("Motor noch kalt");
        };
        disp_zeile_bak[3]=-1;
      }
      ///// Blinker ////
      else if((blinker_start+200)<trip_dist[8] && blinker_lock){ // mal nachfragen wenn nach 200 metern der Blinker noch an ist
        y=get_zeile(zeilen);
        if(disp_zeile_bak[3]!=-2){ // erst die bedingung um den Block abzuklopfen dann gucken ob refresh!
          GLCD.FillRect(0,y,128,15,WHITE);
          GLCD.GotoXY(30,y);
          GLCD.Puts(" *Hmmmm* ");
          y=get_zeile(zeilen);
          GLCD.GotoXY(2,y);
          GLCD.Puts("? Blinker vergessen ?");
        };
        disp_zeile_bak[3]=-2;
      }
      /// die km oder die anziegen von den andern zuständen
      else { 
        switch(trip_mode){
        case 1:   
          sprintf(char_buffer,"%3i.%01ikm T %5i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[8]/1000),(int)floor((trip_dist[8]%1000)/100));
          break;
        case 2:
          sprintf(char_buffer," %3i.%01ikm NP %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[0]/1000),(int)floor((trip_dist[0]%1000)/100));
          break;
        case 3:
          sprintf(char_buffer," %3i.%01ikm D %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[1]/1000),(int)floor((trip_dist[1]%1000)/100));
          break;
        case 4:
          sprintf(char_buffer," %3i.%01ikm R %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[2]/1000),(int)floor((trip_dist[2]%1000)/100));
          break;
        case 5:
          sprintf(char_buffer," %3i.%01ikm Q1 %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100));
          break;
        case 6:
          sprintf(char_buffer," %3i.%01ikm Q2 %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[4]/1000),(int)floor((trip_dist[4]%1000)/100));
          break;
        case 7:
          sprintf(char_buffer," %3i.%01ikm Q3 %3i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[5]/1000),(int)floor((trip_dist[5]%1000)/100));
          break;
        case 8:
          sprintf(char_buffer,"%3i.%01ikm S %5i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[6]/1000),(int)floor((trip_dist[6]%1000)/100));
          break;
        case 9:
          sprintf(char_buffer,"%3i.%01ikm B %5i.%01ikm",(int)floor(trip_dist[3]/1000),(int)floor((trip_dist[3]%1000)/100),(int)floor(trip_dist[7]/1000),(int)floor((trip_dist[7]%1000)/100));
          break;
        };
        y=get_zeile(zeilen);

        if(trip_mode==1){  // das hier ist nur das if für den trip modus ... alles bei 001 als state!!! für die anderen states oben gucken
          if(floor(disp_zeile_bak[3]/100)!=floor(trip_dist[8]/100)+1){ // immer wenn sich trip_dist ändert
            draw_fuel(0,y);
            disp_zeile_bak[3]=trip_dist[8]+100;
            GLCD.FillRect(14,y,114,7,WHITE);
            GLCD.GotoXY(14,y); 
            GLCD.Puts(char_buffer);
            GLCD.FillRect(0,y+8,128,7,WHITE); 
          };
        } 
        else { 
          if(floor(disp_zeile_bak[3]/100)!=floor(trip_dist[8]/100)+1){ // immer wenn sich trip_dist ändert
            disp_zeile_bak[3]=trip_dist[8]+100;
            GLCD.FillRect(0,y,128,7,WHITE); 
            GLCD.GotoXY(0,y);
            GLCD.Puts(char_buffer);
            GLCD.FillRect(0,y+8,128,7,WHITE); 
          };
        };
      };
    };
    ///// Leistung / Warnung //////
    //\\\\\\\\\\\//// var anzeige //////\\\\\\\\\\\\\\
    ///// time //////    
    // außen fixe position
    if(clock_changed()){
      GLCD.FillRect(10,54,48,7,WHITE);
      GLCD.GotoXY(10,63);
      int temptemptemp=menu_state; // keine Ahnung warum, aber clock_copy löscht den menustate, daher retten
      clock_copy(); 
      menu_state=temptemptemp;
      GLCD.Puts(clock_out);
    };
    ///// time ////// 
    ///// GANG //////
    int gang=-1;
    // faktor berechnen
    if((disp_zeile_bak[0]-1)>0){ // hier mal bei zeiten eine neue tabelle mit den richtigen werten ersten, stehen in dz_out_calc
      int faktor=dz_out_disp/(disp_zeile_bak[0]-1);
      if(faktor>45 && faktor<160){
        if(faktor<55)      { gang=6; }
        else if(faktor<63) { gang=5; }
        else if(faktor<73) { gang=4; }
        else if(faktor<90) { gang=3; }
        else if(faktor<120){ gang=2; }
        else               { gang=1; };
      };
    } else {
      gang=-1;  // hier 0 einsetzen für "N" bei 0 km/h oder -1 für keine Ausgabe bei 0 km/h
    };
     
//    Fürs genaue Teilerverhältniss 
//    char temp[10];
//    sprintf(temp,"%i",dz_out_calc/(disp_zeile_bak[0]-1));
//    GLCD.FillRect(68,46,30,7,WHITE);
//    GLCD.GotoXY(69,46);
//    GLCD.Puts(temp);
      
    // wenn gang anders => anzeigen
    if(gang+2!=disp_zeile_bak[8]){
      disp_zeile_bak[8]=gang+2;
      char gear_out[1];
      if(gang==0){
        sprintf(gear_out,"N");
      } else if(gang==-1){
        sprintf(gear_out," ");
      } else {
        sprintf(gear_out,"%1i",gang);
      };
      GLCD.FillRect(68,54,6,7,WHITE);
      GLCD.GotoXY(69,63);
      GLCD.Puts(gear_out);
    };
    ///// GANG //////
    ///// fuel ////// 
    // außen fixe position
    float fuel_temp=fuel_copy();
    if(disp_zeile_bak[7]!=(int)abs(fuel_temp*100)+2){
      int temp1=(int)fuel_temp*10;
      temp1=round(abs(temp1/10));     
      int temp2=(int)abs(fuel_temp*10);
      temp2=temp2%10;
      
      GLCD.FillRect(98,54,30,9,WHITE);
      GLCD.GotoXY(98,63);  
      
      char fuel_out_s[13] ="";
      if(fuel_temp==-100){
        sprintf(fuel_out_s,"");
      } else if(fuel_temp<0) {
        sprintf(fuel_out_s,"-%1i.%il",temp1,temp2);
      } else {
        sprintf(fuel_out_s,"%2i.%il",temp1,temp2);
      };
      GLCD.Puts(fuel_out_s);
      disp_zeile_bak[7]=abs(fuel_temp*100)+2;
    };
    ///// Fuel //////   
    cpr=0;
    int differ_show_tacho=millis()-previousMillis;
//    Serial.print("Normeler Tacho refresh dauerte ");
//    Serial.print(differ_show_tacho);
//    Serial.print(" ms\n");
  }
  //////////////////// Normaler Tacho ///////////////////
  //////////////////// Sprint Tacho ///////////////////
  else if( menu_state==21 ) {
    int sprint_speed=speed_copy();
    if(!sprint_lock){ // ich bin der Meinung das es noch gar nicht losging
      sprint_start=millis();
      sprint_done=false;
      if(sprint_speed>0){ // aber jetzt sollte es losgehen
        sprint_lock=true;
      };
    }
    else if(!sprint_done){ // ich bin unterwegs, aber noch nicht fertig
      if(sprint_speed==0){ // reset
        sprint_lock=false;
      } 
      else if(sprint_speed>=100){ // geschafft
        sprint_done=true;
        sprint_end=millis();
      };
    };
    boolean refresh=false;
    if(!sprint_done && sprint_lock && (millis() - previousMillis > (refresh_interval/3)) ){ // wenn ich noch voll dabei bin alle 200 ms
     refresh=true;
    } else if((millis() - previousMillis > refresh_interval)){ // sonst alle 600 ms
     refresh=true;
    };
    if(refresh){
      char char_buffer[20];
      if(disp_zeile_bak[0]==0){ // wenn es gerade reseted wurde -> alles hinmalen
        GLCD.FillRect(10,25,117,7,WHITE);
        GLCD.GotoXY(40,25);
        sprintf(char_buffer,"%3i km/h",sprint_speed);
        GLCD.Puts(char_buffer);
      }   else if(disp_zeile_bak[0]!=sprint_speed+1){ // wenn er anders ist als beim letzen refresh -> nur Zahl schreiben
        GLCD.FillRect(40,25,18,7,WHITE);
        GLCD.GotoXY(40,25);
        sprintf(char_buffer,"%3i",sprint_speed);
        GLCD.Puts(char_buffer);
      };
      disp_zeile_bak[0]=sprint_speed+1; // zustand sichern 


      unsigned long sprint_time;
      
      if(sprint_done){ // bin fertig mit dem sprint
        sprint_blink_show=!sprint_blink_show;
        sprintf(char_buffer," "); 
        sprint_time=sprint_end - sprint_start;
      }
      else if(sprint_lock){ // ich bin noch dabei
        sprint_time=millis()-sprint_start;
        sprint_blink_show=true;
      } 
      else { // ich steh noch sinnfrei rum
        sprint_time = 0;
        sprint_blink_show=true;
      };
      
      if(disp_zeile_bak[1]==0){ // alles hinschreiben
        disp_zeile_bak[1]=1; // 1 ist nicht 0 und nicht sprint_time+1 => 2. schleife wird gestartet ... 
        sprintf(char_buffer,"%02i,%03i sec",(int)floor(sprint_time/1000),(int)floor((sprint_time%1000)));
        GLCD.GotoXY(35,33);
        GLCD.Puts(char_buffer);
      } else if(disp_zeile_bak[1]!=sprint_time+1){
        disp_zeile_bak[1]=sprint_time+1;
        sprintf(char_buffer,"%02i,%03i",(int)floor(sprint_time/1000),(int)floor((sprint_time%1000)));
        if(sprint_blink_show){
          GLCD.FillRect(35,33,36,8,WHITE);
          GLCD.GotoXY(35,33);
          GLCD.Puts(char_buffer);
        } else {
          GLCD.FillRect(35,33,60,8,WHITE);
          disp_zeile_bak[1]=0;
        };
      };
      previousMillis = millis();  
    };
  }
  //////////////////// Sprint Tacho ///////////////////
  //////////////////// FUEL Tacho ///////////////////
  else if( menu_state==31 ) {
    int zeilen=4;
    zeile=0;
    int y=get_zeile(zeilen);
    char speed_out_s[8];
 
    /////// Speed ///////   
    int temp_speed=speed_copy();
    if(disp_zeile_bak[0]==0){   // zeile 0 noch nicht geschrieben, schreibe die km/h
      sprintf(speed_out_s,"%3i km/h",temp_speed);
      GLCD.FillRect(0,y-4,128,7,WHITE);
      GLCD.GotoXY(40,y-4);
      GLCD.Puts(speed_out_s);
      disp_zeile_bak[0]=temp_speed+1; // haben wir auch im stand nicht diese schleife
    }                                                  // war schon mal in zeile 0 => schreibe nur die zahl, das aber auch nur wenn 1!=x+1 man also nicht steht, bzw stand...
    else if( (abs(disp_zeile_bak[0]-(temp_speed+1))>1) || (abs(disp_zeile_bak[0]-(temp_speed+1))==1 && temp_speed<10) ) { // nur aktualisieren wenn differ 2 km/h oder unter 10 km/h und 1 km/h differ
      sprintf(speed_out_s,"%3i",temp_speed);
      disp_zeile_bak[0]=temp_speed+1;
      GLCD.FillRect(40,y-4,18,7,WHITE);
      GLCD.GotoXY(40,y-4);
      GLCD.Puts(speed_out_s);
    };
    /////// Speed ///////
    /////// Fuel Laden ///////    
    int fuel[3];
    char fuel_out_s[14];
        
    fuel_save(fuel);
//    Serial.print("Fuel geladen: Max ");
//    Serial.print(fuel[0]);
//    Serial.print(" count ");
//    Serial.print(fuel[2]);
//    Serial.print(" DL ");
//    Serial.println(fuel[1]);
    /////// Fuel Laden ///////
    ////// show actual state /////
    y=get_zeile(zeilen);
    if((fuel[2]+1)!=disp_zeile_bak[1]){
      disp_zeile_bak[1]=(fuel[2]+1);
      sprintf(fuel_out_s,"Ticker %03i dLiter %03i",fuel[2],fuel[1]);
      GLCD.FillRect(0,y,128,7,WHITE);
      GLCD.GotoXY(0,y);
      GLCD.Puts(fuel_out_s);
    };
      
    y=get_zeile(zeilen);
    if((fuel[0]+2)!=disp_zeile_bak[2]){
      disp_zeile_bak[2]=(fuel[0]+2);
      sprintf(fuel_out_s,"Max: %02i",fuel[0]);
      GLCD.FillRect(0,y,128,7,WHITE);
      GLCD.GotoXY(0,y);
      GLCD.Puts(fuel_out_s);
    };    
    ////// show actual state /////
    ////// calc amount /////
    y=get_zeile(zeilen);    
    if(fuel_refresh+fuel_last_time_called<millis()){
      int temp_value=fuel[1]*fuel_anzahl+fuel[2]; // centi Liter
      int differ=temp_value-fuel_last_value;
      fuel_last_value=temp_value;     
      
      temp_speed=speed_copy();
      if(temp_speed>0){
        unsigned long temp=100*(3600/temp_speed); // wie lange brauch ich für 100 km => bei 60 km/h 6000 sek ( 1.66 std )
        temp=temp*1000/fuel_refresh*differ; // wieviel fach differ => cl // *1000 da fuel refresh in ms => 6000 sek für 100 km * 1000 / 1000 * differenz zwischen 2 refreshes ( 5 ) = 30000
        temp=temp/fuel_anzahl; // faktor für pulse  30000/25=1200
        int temp_verbrauch_1=round(temp/10); // L/100 km
        int temp_verbrauch_2=temp%10; // die 10 ist noch nicht korrekt 
        
        sprintf(fuel_out_s,"Avg %2i,%01i L/100km",temp_verbrauch_1,temp_verbrauch_2);
      } else {
        sprintf(fuel_out_s," - ");
      };
        
      GLCD.FillRect(0,y,128,7,WHITE);
      GLCD.GotoXY(0,y);
      GLCD.Puts(fuel_out_s);
      fuel_last_time_called=millis();
    };
    ////// calc amount /////
  };
  //////////////////// FUEL Tacho ///////////////////
  //////////////////// bestimmte anzeigen -> aktualisierungsintervall ///////////////////
};
///////////// Loop this //////////////////


